@tool
class_name BaseBuff
extends Resource

@export var buff_id:String
@export var buff_name:String
@export_multiline var buff_desc:String
@export var buff_sprite:Texture2D
## 0代表无限持续时间
@export_range(0,120) var max_duration:float = 3
@export_range(0,10) var time_scale:float = 1
@export_range(0, Constant.INT_MAX) var max_level:int = 1
@export var buff_type:GameEnum.BuffType = GameEnum.BuffType.None
var buff_group:int = GameEnum.BuffGroup.Nothing:
	set(value):
		var temp_value = value
		if buff_group & GameEnum.BuffGroup.Nothing == 0 and value & GameEnum.BuffGroup.Nothing > 0:
			temp_value = GameEnum.BuffGroup.Nothing
		elif buff_group & GameEnum.BuffGroup.Everything == 0 and value & GameEnum.BuffGroup.Everything > 0:
			temp_value = (int)(pow(2,32) - 1) & ~GameEnum.BuffGroup.Nothing
		elif buff_group & GameEnum.BuffGroup.Nothing > 0 and value != GameEnum.BuffGroup.Nothing:
			temp_value = value & ~GameEnum.BuffGroup.Nothing
		elif buff_group & GameEnum.BuffGroup.Everything > 0 and value != (int)(pow(2,32) - 1) & ~GameEnum.BuffGroup.Nothing:
			temp_value = value & ~GameEnum.BuffGroup.Everything
		buff_group = temp_value
@export var buff_tags:Array[String]
@export var conflict_resolution:GameEnum.BuffConflictResolution = GameEnum.BuffConflictResolution.Combine
@export var dispellable:bool = false
@export var demotion:int = -1
var cur_buff_entity:Entity
var provider:Node
var inited:bool = false
var cur_level:int = 0:
	get:return cur_level
	set(value):
		var change_value:int = clamp(value,0,max_level) - cur_level
		on_level_changed.emit(change_value)
		cur_level += change_value
		update_buff_tag()
		if cur_level == 0:
			on_lost_buff.emit()
var residual_duration:float = 0
var buff_tags_cache:Array[String] = []
var buff_tag_dict:Dictionary = {} # level:[tag0,tag1,...]

signal on_get_buff
signal on_lost_buff
signal on_update_buff
signal on_level_changed(change_value:int)
signal on_update_buff_list

func init_buff(provider:Node,buff_entity:Entity):
	if inited:
		push_error("已初始化过！")
	elif buff_entity == null:
		push_error("Buff持有者不能为空")
	else:
		cur_buff_entity = buff_entity
		self.provider = provider
		inited = true
		if demotion < 0:
			demotion = max_level
		if max_duration == 0:
			max_duration = INF
func add_buff_tag(tag:String):
	buff_tags_cache.append(tag)
func add_buff_tags(tags:Array[String]):
	buff_tags_cache.append_array(tags)
func update_buff_tag():
	var cur_tag_level = buff_tag_dict.keys().size()
	if cur_tag_level > cur_level:
		for level in range(cur_level + 1,cur_tag_level + 1):
			if buff_tag_dict.has(level):
				buff_tag_dict.erase(level)
	elif cur_tag_level < cur_level:
		for level in range(cur_tag_level + 1,cur_level + 1):
			if not buff_tag_dict.has(level):
				buff_tag_dict[level] = buff_tags + buff_tags_cache
	buff_tags_cache.clear()
func get_buff_tag_levels(tag:String) -> Array[int]:
	var levels:Array[int] = []
	for level in buff_tag_dict.keys():
		if buff_tag_dict[level].has(tag):
			levels.append(level)
	return levels
func remove_buff_by_tag(tag:String) -> int:
	var new_level = 1
	var new_buff_tag_dict = {}
	var remove_count:int = 0
	for level in buff_tag_dict.keys():
		if not buff_tag_dict[level].has(tag):
			new_buff_tag_dict[new_level] = buff_tag_dict[level]
			new_level += 1
		else:
			remove_count += 1
	buff_tag_dict = new_buff_tag_dict
	return remove_count
func _get_one_count(num):
	var count = 0
	while num > 0:
		if num & 1 > 0:
			count += 1
		num >>= 1
	return count
func _get_hint_string() -> String:
	var arr = []
	for key in GameEnum.BuffGroup.keys():
		## 去掉方便操作的复合类型
		if _get_one_count(GameEnum.BuffGroup[key]) == 1:
			arr.append(key)
	return ",".join(arr)
func _get_property_list():
	var properties = []

	properties.append({
		"name" = "buff_group",
		"type" = TYPE_INT,
		"usage" = PROPERTY_USAGE_DEFAULT,
		"hint" = PROPERTY_HINT_FLAGS,
		"hint_string" = _get_hint_string(),
	})
	return properties
